<template>
  <div>
    <div class="tree-transfer">
      <div>
        <div style="padding:5px;width:240px;border: 1px solid #d0d3d9;">
          <el-input v-model="filterLeftText" placeholder="输入姓名" :suffix-icon="Search" />
        </div>
        <el-scrollbar style="padding:5px;width:240px;height:300px;border: 1px solid #d0d3d9;border-top:0px;">
          <el-tree ref="treeLeftRef" :data="fromDataLeft" :props="props.defaultProps" show-checkbox default-expand-all
            :node-key="props.defaultProps.value" highlight-current @check-change="leftCheckChange"
            :filter-node-method="filterLeftNode" style="max-width: 260px" />
        </el-scrollbar>
      </div>
      <div style="width: 30px;margin: auto 15px;">
        <el-button style="width:24px;" type="primary" @click="toRight" :icon="ArrowRight" />
        <el-button style="width:24px;margin: 10px 0 0 0!important;" @click="toLeft" type="primary" :icon="ArrowLeft" />
      </div>
      <div>
        <div style="padding:5px;width:240px;border: 1px solid #d0d3d9;">
          <el-input v-model="filterRightText" placeholder="输入姓名" :suffix-icon="Search" />
        </div>
        <div style="padding:5px;width:240px;height:300px;border: 1px solid #d0d3d9;border-top:0px;">
          <el-scrollbar>
            <div style="padding:5px;">已选</div>
            <el-tree ref="treeRightRef" :data="fromDataRight" :props="props.defaultProps" show-checkbox default-expand-all
              :node-key="props.defaultProps.value" highlight-current @check-change="rightCheckChange"
              :filter-node-method="filterRightNode" style="max-width: 260px" />
          </el-scrollbar>
        </div>
      </div>
    </div>
    <div style="width:100%;height:1px;background-color:#d0d3d9;margin-top:30px;"></div>
  </div>
</template>

<script setup name="TreeTransfer">
import {
  ref,
  reactive,
  watch,
  onMounted
} from 'vue'
import { ArrowLeft } from '@element-plus/icons-vue'
import { ArrowRight } from '@element-plus/icons-vue'
import { Search } from '@element-plus/icons-vue'
const {
  proxy
} = getCurrentInstance();

const props = defineProps({
  data: {
    type: Array,
    default: () => []
  },
  defaultProps: {
    type: Object,
    default: () => {
      return {
        children: 'children',
        label: 'label',
        value: 'value',
      }
    }
  },
  defaultCheckedKeys: {
    type: Array,
    default: () => []
  },
  height: {
    type: String,
    default: '300px'
  }
});

const emits = defineEmits(['update:toData']);

// 左侧树展示数据
const fromDataLeft = props.defaultCheckedKeys.length > 0 ? ref(findNonMatches(props.data, props.defaultCheckedKeys)) :
  ref(JSON.parse(JSON.stringify(props.data)));
// 左侧半选择数据列表
let leftHalfChecked = [];
// 右侧树展示数据
const fromDataRight = props.defaultCheckedKeys.length > 0 ? ref(findMatches(props.data, props.defaultCheckedKeys)) :
  ref([]);
// 右侧半选择数据列表
let rightHalfChecked = [];
// 最终显示的选择数据
const toData = props.defaultCheckedKeys && props.defaultCheckedKeys.length > 0 ? ref(props.defaultCheckedKeys) : ref(
  []);

// 初始化默认传给到父层获取数据的数组
emits("update:toData", [...toData.value]);

/** 递归获取所有id */
function extractIds(arr) {
  const ids = [];

  for (const item of arr) {
    ids.push(item[props.defaultProps.value]);

    if (item.children) {
      const childIds = extractIds(item.children);
      ids.push(...childIds);
    }
  }

  return ids;
}

/** 递归筛选匹配的id */
function findMatches(arr1, arr2, matches = true) {
  const result = [];

  arr1.forEach(item => {
    const match = arr2.includes(item[props.defaultProps.value]);
    if ((matches && match) || (!matches && !match)) {
      const newItem = {
        ...item
      };
      if (newItem.children) {
        newItem.children = findMatches(newItem.children, arr2, matches);
      }
      result.push(newItem);
    }
  });

  return result;
}

/** 递归筛选非匹配的id */
function findNonMatches(arr1, arr2) {
  const result = [];

  arr1.forEach(item => {
    const match = arr2.includes(item[props.defaultProps.value]);
    if (!match) {
      const newItem = {
        ...item
      };
      if (newItem.children) {
        newItem.children = findNonMatches(newItem.children, arr2);
      }
      result.push(newItem);
    }
  });

  return result;
}

/** 将两个数组合并为新数组*/
function concatData(arr1, arr2) {
  const uniqueValues = new Set([...arr1, ...arr2]);
  const newData = Array.from(uniqueValues);
  return newData;
}

// 左侧相关
const treeLeftRef = ref(null);
const filterLeftText = ref("");
const toLeftData = ref([]);

/** 左侧数选择 */
const getLeftCheckedNodes = () => {
  return treeLeftRef.value.getCheckedNodes(false, false)
}
const getLeftCheckedKeys = () => {
  return treeLeftRef.value.getCheckedKeys(false)
}

function leftCheckChange(data, checked, indeterminate) {
  leftHalfChecked = treeLeftRef.value.getHalfCheckedKeys();
  toLeftData.value = getLeftCheckedKeys();
}
const filterLeftNode = (value, data) => {
  if (!value) return true
  return data.label.includes(value)
}
watch(filterLeftText, (val) => {
  treeLeftRef.value.filter(val)
});


// 右侧相关
const treeRightRef = ref(null);
const filterRightText = ref("");
const toRightData = ref([]);

/** 左侧数选择 */
const getRightCheckedNodes = () => {
  return treeRightRef.value.getCheckedNodes(false, false);
}
const getRightCheckedKeys = () => {
  return treeRightRef.value.getCheckedKeys(false);
}

function rightCheckChange(data, checked, indeterminate) {
  rightHalfChecked = treeRightRef.value.getHalfCheckedKeys();
  toRightData.value = getRightCheckedKeys();
}
const filterRightNode = (value, data) => {
  if (!value) return true
  return data.label.includes(value)
}
watch(filterRightText, (val) => {
  treeRightRef.value.filter(val)
});

// 点击想着按钮函数
function toLeft() {
  let leftData = [...rightHalfChecked, ...toRightData.value, ...extractIds(fromDataLeft.value)];
  fromDataLeft.value = findMatches(props.data, leftData);
  fromDataRight.value = findNonMatches(fromDataRight.value, [...toRightData.value]);
  toData.value = extractIds(fromDataRight.value);
  emits("update:toData", [...toData.value]);
  toLeftData.value = [];
  toRightData.value = [];
  leftHalfChecked = [];
  rightHalfChecked = [];
}

// 点击向右按钮函数
function toRight() {
  toData.value = concatData(toData.value, [...toLeftData.value]);
  fromDataLeft.value = findNonMatches(fromDataLeft.value, [...toLeftData.value]);
  let rightData = [...leftHalfChecked, ...extractIds(fromDataRight.value), ...toLeftData.value];
  fromDataRight.value = findMatches(props.data, rightData);
  emits("update:toData", [...toData.value]);
  toLeftData.value = [];
  toRightData.value = [];
  leftHalfChecked = [];
  rightHalfChecked = [];
}
</script>

<style lang="scss" scoped>
.tree-transfer {
  display: flex;
  width: 100%;
  justify-content: center;
}
</style>